﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace KillParser
{
    public class KillMail
    {
        #region properties

        private DateTime killTime;

        public DateTime KillTime
        {
            get { return killTime; }
        }

        private string originalKillText;

        public string OriginalKillText
        {
            get { return originalKillText; }
        }

        private Pilot victim = new Pilot();

        public Pilot Victim
        {
            get { return victim; }
        }

        private List<Pilot> involved = new List<Pilot>();

        public List<Pilot> Involved
        {
            get { return involved; }
        }

        private StarSystem fightSystem = new StarSystem();

        public StarSystem FightSystem
        {
            get { return fightSystem; }
        }

        private List<Item> itemCasualties = new List<Item>();

        public List<Item> ItemCasualties
        {
            get { return itemCasualties; }
        }

        #endregion

        public KillMail() { }

        public void Parse(string killText)
        {
            originalKillText = killText;
            Parse();
        }

        public void Parse(FileInfo killFile)
        {
            using (TextReader tr = killFile.OpenText())
            {
                Parse(tr);
            }
        }

        public void Parse(TextReader tr)
        {
            string killText = tr.ReadToEnd();
            Parse(killText);
        }

        public void Parse()
        {
            if (originalKillText == null || originalKillText.Trim().Length == 0)
            {
                throw new BadKillException("Kill text is empty.");
            }

            StringReader sr = new StringReader(originalKillText);

            ParseDate(sr);
            ParseVictim(sr);
            ParseInvolved(sr);

            sr.Close();
            sr = new StringReader(originalKillText);
            ParseItems(sr, "dropped items:");

            sr.Close();
            sr = new StringReader(originalKillText);
            ParseItems(sr, "destroyed items:");


        }



        private void ParseVictim(StringReader sr)
        {
            string inputLine = sr.ReadLine();

            Dictionary<string, string> VictimInfo = new Dictionary<string, string>();

            while (inputLine != null && !inputLine.Trim().Equals("Involved parties:", StringComparison.CurrentCultureIgnoreCase))
            {
                if (inputLine.Trim().Length == 0)
                {
                    inputLine = sr.ReadLine();
                    continue;
                }

                string[] splitz = inputLine.Split(':');
                if (splitz.Length != 2)
                {
                    throw new BadKillException("Victim info has an incorrect name/value pair");
                }

                string key = splitz[0].Trim().ToLower();
                string value = splitz[1].Trim();

                VictimInfo.Add(key, value);

                inputLine = sr.ReadLine();
            }

            victim.Name = VictimInfo["victim"];
            victim.CorpName = VictimInfo["corp"];
            victim.Alliance = VictimInfo["alliance"];
            victim.Faction = VictimInfo["faction"];
            victim.Ship = VictimInfo["destroyed"];
            victim.DamageTakenOrDone = Convert.ToInt16(VictimInfo["damage taken"]);

            fightSystem.Name = VictimInfo["system"];
            fightSystem.SecStatus = (float)Convert.ToDouble(VictimInfo["security"]);

        }

        private void ParseDate(StringReader sr)
        {
            string inputLine = sr.ReadLine();

            try
            {
                killTime = DateTime.ParseExact(inputLine, "yyyy.MM.dd HH:mm:ss", null);
            }
            catch (Exception e)
            {
                throw new BadKillException("Bad Killdate", e);
            }
                
        }

        private void ParseInvolved(StringReader sr)
        {
            string inputLine;

            List<Dictionary<string, string>> involvedRaw = new List<Dictionary<string, string>>();
            Dictionary<string, string> rawData = new Dictionary<string,string>();


            while((inputLine = sr.ReadLine()) != null && 
                !inputLine.Trim().Equals("dropped items:", StringComparison.CurrentCultureIgnoreCase) &&
                !inputLine.Trim().Equals("destroyed items:", StringComparison.CurrentCultureIgnoreCase))
            {

                if (inputLine.Trim().Length == 0)
                {
                    if (rawData.Count > 0)
                    {
                        involvedRaw.Add(rawData);
                        rawData = new Dictionary<string, string>();
                    }
                    continue;
                }

                string[] splitz = inputLine.Split(':');
                if (splitz.Length != 2)
                {
                    throw new BadKillException("Involved info has a malformed name/value pair");
                }

                string key = splitz[0].Trim().ToLower();
                string value = splitz[1].Trim();

                rawData.Add(key, value);

            }

            foreach (Dictionary<string, string> raw in involvedRaw)
            {
                
                Pilot killer = new Pilot();

                killer.Alliance = GetSafeString(raw , "alliance");
                killer.CorpName = GetSafeString(raw, "corp");
                killer.DamageTakenOrDone = Convert.ToInt16(GetSafeString(raw ,"damage done"));
                killer.Faction = GetSafeString(raw, "faction");
                killer.SecStatus = (float)Convert.ToDouble(GetSafeString(raw, "security"));
                killer.Ship = GetSafeString(raw, "ship");
                killer.Weapon = GetSafeString(raw, "weapon");

                string name = raw["name"];
                if (name.Contains("(laid the final blow)"))
                {
                    name = name.Replace("(laid the final blow)", "");
                    killer.LaidTheFinalBlow = true;
                }

                killer.Name = name;

                Involved.Add(killer);
            }
        }

        private string GetSafeString(Dictionary<string, string> raw, string p)
        {
            if (raw.ContainsKey(p))
            {
                return raw[p];
            }
            else
            {
                return null;
            }
        }

        private void ParseItems(StringReader sr, string itemType)
        {
            
            string inputLine;

            //seek to itemType

            while ((inputLine = sr.ReadLine()) != null && !inputLine.Equals(itemType, StringComparison.CurrentCultureIgnoreCase)) ;

            if (inputLine == null)
            {
                return;
            }

            while ((inputLine = sr.ReadLine()) != null &&
                !inputLine.Equals("dropped items:", StringComparison.CurrentCultureIgnoreCase) &&
                !inputLine.Equals("destroyed items:", StringComparison.CurrentCultureIgnoreCase))
            {
                if (inputLine.Trim().Length == 0)
                {
                    //skip blanks
                    continue;
                }
                Item i = ParseSingleItem(inputLine);
                if (itemType == "dropped items:")
                {
                    i.WasDestroyed = false;
                }
                else
                {
                    i.WasDestroyed = true;
                }

                itemCasualties.Add(i);
               
            }
        }

        private Item ParseSingleItem(string inputLine)
        {
            Item i = new Item();

            i.InCargo = false;
            if (inputLine.Contains("(Cargo"))
            {
                inputLine = inputLine.Replace("(Cargo)", "");
                i.InCargo = true;
            }

            string[] splitz = inputLine.Split(',');

            if (splitz.Length > 1)
            {
                //got quantity
                string qty = splitz[1].ToLower().Replace("qty:", "").Trim();
                i.ItemQty = Convert.ToInt16(qty);
            }
            else
            {
                i.ItemQty = 1;
            }

             i.ItemName = splitz[0];

            return i;
        }

        public string GenerateText()
        {
            string crlf = "\r\n";
            StringBuilder sb = new StringBuilder();

            return sb.ToString();
        }
    }

}
